package com.zhiyin.seal.service.impl;

import com.google.common.collect.Maps;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.zhiyin.seal.dao.FileDao;
import com.zhiyin.seal.entity.ApplyAttachmentEntity;
import com.zhiyin.seal.entity.ImageEntity;
import com.zhiyin.seal.entity.bo.*;
import com.zhiyin.seal.service.FileService;
import com.zhiyin.seal.util.*;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class FileServiceImpl implements FileService {

    @Autowired
    FileDao fileDao;

    @Value("${myconfig.file-path}")
    String filePath;

    @Value("${myconfig.domain}")
    private String domain;

    @Value("${myconfig.attachment-download}")
    private String attachmentDownload;

    @Override
    public String uploadImage(ImageBo imageBo, MultipartFile file) {
        // 判断存储目录是否存在，不存在则创建目录
        File imgFileDir = new File(imageBo.getImagePath());
        if(!imgFileDir.exists()){
            imgFileDir.mkdirs();
        }
        // 读取文件后缀名
        String originalFilename = file.getOriginalFilename().toLowerCase();
        //生成图片的绝对存储路径
        String[] strs = originalFilename.split("\\.");
        // 判断是否存在后缀名
        if(strs.length < 2){
            return null;
        }
        //获取源文件后缀名
        String extension =  strs[1];
        String fileName =  UUIDUtil.getUUIDString() + "." + extension;
        String fillPath = imageBo.getImagePath() + "/" + fileName;
        imageBo.setImageName(fileName);
        try {
            FileOutputStream fos = new FileOutputStream(fillPath);
            byte[] buffer = file.getBytes();
            if(buffer != null && buffer.length > 0) {
                fos.write(buffer);
                fos.flush();
                fos.close();

                // 插入数据
                Integer result = fileDao.insertImage(BeanUtil.copy(imageBo, ImageEntity.class));
                if(result > 0){
                    return fileName;
                }

                return null;
            }
        }
        catch(Exception ex) {

        }

        return null;
    }

    @Override
    public Boolean uploadAttachment(ApplyAttachmentBo attachmentBo, MultipartFile file) {
        // 判断存储目录是否存在，不存在则创建目录
        File fileDir = new File(attachmentBo.getFilePath());
        if(!fileDir.exists()){
            fileDir.mkdirs();
        }
        // 读取原始文件名称
        String originalFilename = file.getOriginalFilename().toLowerCase();
        attachmentBo.setOriginalName(originalFilename);
        String[] strs = originalFilename.split("\\.");
        // 判断是否存在后缀名
        if(strs.length < 2){
            return null;
        }
        //获取源文件后缀名
        String extension =  strs[1];
        attachmentBo.setExtensionName(extension);
        // 服务器存储名称
        String fileName =  UUIDUtil.getUUIDString() + "." + extension;
        attachmentBo.setFileName(fileName);
        // 读取content-type
        String contentType = file.getContentType();
        attachmentBo.setMimeType(contentType);
        // 文件大小
        Long length = file.getSize();
        attachmentBo.setLength(length);
        // 保存的文件完整路径
        String fillPath = attachmentBo.getFilePath() + "/" + fileName;
        try {
            FileOutputStream fos = new FileOutputStream(fillPath);
            byte[] buffer = file.getBytes();
            if(buffer != null && buffer.length > 0) {
                fos.write(buffer);
                fos.flush();
                fos.close();
                // 拼接下载链接
                String fileUrl = domain + attachmentDownload + "?fileName=" + fileName;
                attachmentBo.setFileUrl(fileUrl);
                // 插入数据
                return fileDao.insertApplyAttachment(BeanUtil.copy(attachmentBo, ApplyAttachmentEntity.class)) > 0;
            }
        }
        catch(Exception ex) {

        }

        return false;
    }

    @Override
    public FileSystemResource downloadAttachment(String fileName) {
        ApplyAttachmentBo attachmentBo = BeanUtil.copy(fileDao.selectApplyAttachment(fileName),ApplyAttachmentBo.class);
        if(attachmentBo != null){
            String filePath = attachmentBo.getFilePath() + "/" + fileName;
            File f = new File(filePath);
            if(f.exists()) {
                return new FileSystemResource(filePath);
            }
        }

        return null;
    }

    @Override
    public ApplyAttachmentBo getAttachmentByFileName(String fileName) {
        ApplyAttachmentEntity attachmentEntity = fileDao.selectApplyAttachment(fileName);
        if(attachmentEntity != null){
            return BeanUtil.copy(attachmentEntity,ApplyAttachmentBo.class);
        }

        return null;
    }

    @Override
    public List<ApplyAttachmentBo> getAttachmentListByApplyId(Long applyId) {
        List<ApplyAttachmentEntity> attachmentEntityList = fileDao.selectApplyAttachmentList(applyId);
        if(attachmentEntityList != null){
            return BeanUtil.copyList(attachmentEntityList,ApplyAttachmentBo.class);
        }

        return null;
    }

    @Override
    public Boolean updateAttachmentApplyId(Long applyId, List<String> fileUrls) {
        return fileDao.updateAttachmentApplyId(applyId,fileUrls) > 0;
    }

    @Override
    public FileSystemResource downloadImage(String imageName) {
        ImageBo imageBo = BeanUtil.copy(fileDao.selectImage(imageName),ImageBo.class);
        if(imageBo != null){
            String filePath = imageBo.getImagePath() + "/" + imageName;
            File f = new File(filePath);
            if(f.exists()) {
                return new FileSystemResource(filePath);
            }
        }
        return null;
    }

    @Override
    public FileSystemResource downloadPdf(String fileName, Long companyId, Integer type) {
        String fileType = type == 1 ? "apply":"stamp";
        String pdfPath = filePath + "/" + companyId + "/" + fileType + "/" + fileName;
        File f = new File(pdfPath);
        if(f.exists()){
            return new FileSystemResource(pdfPath);
        }

        return null;
    }

    @Override
    public void exportFile(Integer exportType, List<ApplyBo> applyBoList, HttpServletResponse response) {
        if(applyBoList != null && applyBoList.size() > 0){
            Map<Long,ApplyBo> applyBoMap = Maps.newHashMap();
            for (ApplyBo applyBo : applyBoList) {
                applyBoMap.put(applyBo.getId(),applyBo);
            }
            ZipOutputStream zipos = null;
            OutputStream outputStream = null;
            // 创建字节数组输出流用于os的写出操作
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                outputStream = response.getOutputStream();
                zipos = new ZipOutputStream(new BufferedOutputStream(baos));
                zipos.setMethod(ZipOutputStream.DEFLATED); //设置压缩方法
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
            DataOutputStream os = null;
            int fileIndex =1;
            for(ApplyBo applyBo : applyBoMap.values()){
                String fileUrl = null;
                if(exportType.equals(1)){
                    fileUrl = applyBo.getApplyPdfUrl();
                } else if(exportType.equals(2)){
                    fileUrl = applyBo.getStampPdfUrl();
                }
                if(fileUrl != null){
                    String fileName = fileUrl.split("\\?")[1].split("&")[0].split("=")[1];
                    FileSystemResource fileSystemResource = downloadPdf(fileName,applyBo.getCompanyId(),exportType);
                    if(fileSystemResource != null){
                        String newFileName = fileIndex + "-" + applyBo.getReason();
                        if(newFileName.length() > 18){
                            newFileName = newFileName.substring(0,15) + "***";
                        }
                        newFileName = newFileName + ".pdf";
                        try {
                            zipos.putNextEntry(new ZipEntry(newFileName));
                            os = new DataOutputStream(zipos);
                            FileInputStream is =  new FileInputStream(fileSystemResource.getFile());
                            byte[] b = new byte[1024];
                            int length = 0;
                            while((length = is.read(b))!= -1){
                                os.write(b, 0, length);
                            }
                            is.close();
                            zipos.closeEntry();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        fileIndex++;
                    }
                }

            }
            // 压缩包名称
            String zipName = "";
            if(exportType.equals(1)){
                zipName = "apply_file_"+System.currentTimeMillis()+".zip";
            } else if(exportType.equals(2)){
                zipName = "stamp_file_"+System.currentTimeMillis()+".zip";
            }
            //关闭流
            try {
                if(os != null){
                    os.flush();
                    os.close();
                }
                zipos.close();
                // 设置response的Header
                response.setCharacterEncoding("UTF-8");
                response.setContentType("application/octet-stream");
                response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(zipName,"UTF-8"));
                outputStream.write(baos.toByteArray());
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void exportApply(ApplyDetailBo applyDetailBo, HttpServletResponse response) {
        if(applyDetailBo != null){
            // 生成文件名
            String fileName = UUIDUtil.getUUIDString(false) + ".pdf";
            // 生成pdf缓存路径
            String pdfFilePath = filePath + "/" + applyDetailBo.getCompanyId() + "/" + fileName;
            Document document = new Document(PageSize.A4);
            try {
                FileOutputStream fileOutputStream = new FileOutputStream(pdfFilePath);
                PdfWriter writer = PdfWriter.getInstance(document, fileOutputStream);
                // 设置水印
                HeaderFooter header = new HeaderFooter(null,applyDetailBo.getCompanyInfo().getName());
                writer.setPageEvent(header);
                // 打开文档
                document.open();
                // 设置字体
                BaseFont bfChinese = BaseFont.createFont("STSongStd-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
                // 插入单据表格信息
                Font f = new Font(bfChinese, 12, Font.NORMAL);
                f.setFamily("微软雅黑");
                PdfPTable table =  new PdfPTable(4);
                int headerWidths[] = {20, 25, 25, 25};
                table.setWidths(headerWidths);
                table.setWidthPercentage(100);
                table.getDefaultCell().setBorderWidth(2);

                // 申请人信息
                table.addCell(new MyPdfPcell(true,new Phrase("单据编号",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(applyDetailBo.getCode())));
                table.addCell(new MyPdfPcell(true,new Phrase("提交时间",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(DateUtil.COMMON_DATE_FORMATE.format(applyDetailBo.getCreateTime()),f)));
                table.addCell(new MyPdfPcell(true,new Phrase("申请人",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(applyDetailBo.getApplyUserInfo().getNickName(),f)));
                table.addCell(new MyPdfPcell(true,new Phrase("审批状态",f)));
                // 审批状态，0：待审批，1：审批中，2：审批通过，3：已驳回，4：已撤销，5：已关闭
                Map<Integer,String> mapStatus = Maps.newHashMap();
                mapStatus.put(0,"待审批");
                mapStatus.put(1,"审批中");
                mapStatus.put(2,"审批通过");
                mapStatus.put(3,"已驳回");
                mapStatus.put(4,"已撤销");
                mapStatus.put(5,"已关闭");
                table.addCell(new MyPdfPcell(false,new Phrase(mapStatus.get(applyDetailBo.getApprovalStatus()),f)));
                table.completeRow();
                // 申请内容标题
                PdfPCell cellApplyTile = new MyPdfPcell(true,new Phrase("申请内容",f));
                cellApplyTile.setColspan(4);
                table.addCell(cellApplyTile);
                table.completeRow();
                // 单据详情
                table.addCell(new MyPdfPcell(true,new Phrase("用印事由",f)));
                PdfPCell cellReason = new MyPdfPcell(false,new Phrase(applyDetailBo.getReason(),f));
                cellReason.setColspan(3);
                table.addCell(cellReason);
                table.completeRow();
                table.addCell(new MyPdfPcell(true,new Phrase("文件名称",f)));
                PdfPCell cellFileName = new MyPdfPcell(false,new Phrase(applyDetailBo.getFileName(),f));
                cellFileName.setColspan(3);
                table.addCell(cellFileName);
                table.completeRow();
                table.addCell(new MyPdfPcell(true,new Phrase("文件类型",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(applyDetailBo.getFileType(),f)));
                table.addCell(new MyPdfPcell(true,new Phrase("文件份数",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(applyDetailBo.getFileNumber().toString(),f)));
                table.addCell(new MyPdfPcell(true,new Phrase("盖章次数",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(applyDetailBo.getApplyCount().toString(),f)));
                table.addCell(new MyPdfPcell(true,new Phrase("用印截至时间",f)));
                table.addCell(new MyPdfPcell(false,new Phrase(DateUtil.COMMON_DATE_FORMATE.format(applyDetailBo.getExpireTime()),f)));
                table.completeRow();
                // 审批流程
                PdfPCell cellApprovalTile = new MyPdfPcell(true,new Phrase("审批流程",f));
                cellApprovalTile.setColspan(4);
                cellApprovalTile.setHorizontalAlignment(Paragraph.ALIGN_CENTER);
                table.addCell(cellApprovalTile);
                table.completeRow();
                table.addCell(new MyPdfPcell(true,new Phrase("审批节点",f)));
                table.addCell(new MyPdfPcell(true,new Phrase("审批人",f)));
                table.addCell(new MyPdfPcell(true,new Phrase("审批意见",f)));
                table.addCell(new MyPdfPcell(true,new Phrase("操作时间",f)));
                table.completeRow();
                // 审批人
                if(applyDetailBo.getApprovalList() != null){
                    List<MyApprovalBo> approvalList = applyDetailBo.getApprovalList();
                    List<String> nameList = Lists.newArrayList();
                    int level = -1;
                    String name = "";
                    String handlerTime = "";
                    String opinion = "";
                    for (MyApprovalBo myApprovalBo : approvalList) {
                        if(!myApprovalBo.getLevel().equals(level)){
                            if(nameList.size() > 0){
                                name = String.join(",",nameList);
                                table.addCell(new MyPdfPcell(true,new Phrase("审批人",f)));
                                table.addCell(new MyPdfPcell(true,new Phrase(name,f)));
                                table.addCell(new MyPdfPcell(true,new Phrase(opinion,f)));
                                table.addCell(new MyPdfPcell(true,new Phrase(handlerTime,f)));
                                table.completeRow();
                                nameList.clear();
                            }
                            level = myApprovalBo.getLevel();
                            opinion = myApprovalBo.getOpinion();
                            handlerTime = DateUtil.COMMON_DATE_FORMATE.format(myApprovalBo.getUpdateTime());
                        }
                        nameList.add(myApprovalBo.getUserInfo().getNickName());
                    }
                    if(nameList.size() > 0){
                        name = String.join(",",nameList);
                        table.addCell(new MyPdfPcell(true,new Phrase("审批人",f)));
                        table.addCell(new MyPdfPcell(true,new Phrase(name,f)));
                        table.addCell(new MyPdfPcell(true,new Phrase(opinion,f)));
                        table.addCell(new MyPdfPcell(true,new Phrase(handlerTime,f)));
                        table.completeRow();
                        nameList.clear();
                    }
                }
                // 抄送人
                if(applyDetailBo.getCcList() != null){
                    List<MyCCBo> ccList = applyDetailBo.getCcList();
                    List<String> nameList = Lists.newArrayList();
                    for (MyCCBo myCCBo : ccList) {
                        nameList.add(myCCBo.getUserInfo().getNickName());
                    }
                    if(nameList.size() > 0){
                        table.addCell(new MyPdfPcell(true,new Phrase("抄送人",f)));
                        String name = String.join(",",nameList);
                        PdfPCell cellCCName = new MyPdfPcell(true,new Phrase(name,f));
                        cellCCName.setColspan(3);
                        table.addCell(cellCCName);
                        table.completeRow();
                    }
                }
                document.add(table);

                // 插入文件二维码
                BarcodeQRCode barcodeQRCode = new BarcodeQRCode(applyDetailBo.getApplyPdfUrl(), 100, 100, null);
                Image codeQrImage = barcodeQRCode.getImage();
                codeQrImage.setAlignment(Image.ALIGN_CENTER);
                document.add(codeQrImage);
                f = new Font(bfChinese,11, Font.NORMAL);
                f.setFamily("微软雅黑");
                Paragraph pQRCode = new Paragraph("微信扫描查看电子文档",f);
                pQRCode.setAlignment(Paragraph.ALIGN_CENTER);
                document.add(pQRCode);

            } catch(Exception ex){

            } finally {
                try {
                    // 关闭PDF文档
                    if(document.isOpen()){
                        document.close();
                    }
                    // 设置response的Header
                    response.setCharacterEncoding("UTF-8");
                    response.setContentType("application/octet-stream");
                    response.setHeader("Content-Disposition", "attachment;filename="+ URLEncoder.encode(fileName, "UTF-8"));
                    // 将PDF文件输出到响应流
                    File file  = new File(pdfFilePath);
                    FileInputStream fileInputStream  = new FileInputStream(file);
                    ServletOutputStream out = response.getOutputStream();
                    byte buff[] = new byte[1024];
                    int length = 0;
                    while ((length = fileInputStream.read(buff)) > 0) {
                        out.write(buff,0,length);

                    }
                    // 关闭流
                    fileInputStream.close();
                    out.close();
                    out.flush();
                    // 删除文件
                    file.delete();
                } catch (Exception ex) {

                }
            }

        }
    }
}
